/*CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
 C      process_queue.c
 C      Application Name: tcss422-project2
 C      Programmers Names: Evan Phillips, Lucas Cowell, Tony Butterfield
 C      Date created:   May 9, 2011
 C      Date Completed: June 2, 2011
 C      Brief Description: An implementation of a queue of processes for the simulation of an OS
 C          scheduler.
 C
 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC*/
#include <stdlib.h>
#include <stddef.h>

#include "definitions.h"
#include "process_queue.h"
#include "process.h"

/*=================================================================================================
 =  Comment block for function: p_queue_init()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      ProcessQueue p_queue_init()
 =      Return value ranges: Initialized pointer to empty queue
 =      Parameter value ranges: N/a
 =      Error conditions: N/a
 =  Initializes an empty queue of Processes.
 =
 ==================================================================================================*/
ProcessQueue p_queue_init()
{
	ProcessQueue pqp = (ProcessQueue) malloc(sizeof(ProcQueueStr));
	pqp->first = NULL;
	pqp->last = NULL;
	pqp->size = 0;

	return pqp;
}


/*=================================================================================================
 =  Comment block for function: p_queue_free()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      void p_queue_free(ProcessQueue)
 =      Return value ranges: n/a
 =      Parameter value ranges: A pointer to a ProcessQueueStr
 =      Error conditions: N/a
 =  Dequeues all elements from the queue (freeing each node as a result) then freeing the memory
 =  allocated for the queue struct itself.
 =
 ==================================================================================================*/
int p_queue_free(ProcessQueue q)
{
    int error = 0;

    if (q == NULL) return NULL_POINTER_ERROR;
    while(!p_queue_isEmpty(q, &error))
    {
        p_queue_dequeue(q, &error);     // empty queue and free() nodes (no automatic gc!)
    }
	free(q);
	return error;
}


/*=================================================================================================
 =  Comment block for function: p_queue_enqueue()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      int p_queue_enqueue(ProcessQueue, Process)
 =      Return value ranges: 0 on success, error code otherwise
 =      Parameter value ranges: A pointer to a ProcessQueueStr and a process
 =      Error conditions: NULL_POINTER_ERROR
 =  creates a new QueueNode with the pointer to the process and inserts it at the end of the queue.
 =
 ==================================================================================================*/
int p_queue_enqueue(ProcessQueue q, Process p)
{
    if (q == NULL || p == NULL) return NULL_POINTER_ERROR;


	QueueNode n = (QueueNode) malloc(sizeof(QueueNodeStr));// remember each malloc() must be free()'d
	n->data = p;
	n->next = NULL;

	if(q->first == NULL)
		q->first = q->last = n;
	else
	{
		q->last->next = n;
		q->last = n;
	}
	q->size++;
	return 0;
}

/*=================================================================================================
 =  Comment block for function: p_queue_dequeue()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      Process p_queue_dequeue(ProcessQueue)
 =      Return value ranges: pointer to a ProcessStr
 =      Parameter value ranges: A pointer to a ProcessQueueStr
 =      Error conditions: returns NULL if queue is empty.
 =  returns the pointer stored in the first node, reassigns the first pointer to the next node in
 =  the queue and deallocates the memory allocated to the dequeue'd node.
 =
 ==================================================================================================*/
Process p_queue_dequeue(ProcessQueue q, int* error)
{
    if (q == NULL)
    {
        *error |= NULL_POINTER_ERROR;
        return NULL;
    }

    Process p = NULL;

    if (!p_queue_isEmpty(q, error))
    {
        QueueNode n = q->first;
        p = n->data;
        q->first = n->next;
        q->size--;
        free(n);
    }

    return p;
}

/*=================================================================================================
 =  Comment block for function: p_queue_peek()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      Process p_queue_dequeue(ProcessQueue)
 =      Return value ranges: pointer to a ProcessStr
 =      Parameter value ranges: A pointer to a ProcessQueueStr
 =      Error conditions: returns NULL if queue is empty.
 =  returns the pointer stored in the first node.
 =
 ==================================================================================================*/
Process p_queue_peek(ProcessQueue q, int* error)
{
    if (q == NULL)
    {
        *error |= NULL_POINTER_ERROR;
        return NULL;
    }

	Process p = NULL;
    if(!p_queue_isEmpty(q, error))
	{
	    p = q->first->data;
	}
    return p;
}

/*=================================================================================================
 =  Comment block for function: p_queue_size()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      int p_queue_size(ProcessQueue)
 =      Return value ranges: unsigned short
 =      Parameter value ranges: A pointer to a ProcessQueueStr
 =      Error conditions: returns NULL_POINTER_ERROR if pointer is null.
 =  returns the number of Process' stored in the queue.
 =
 ==================================================================================================*/
int p_queue_size(ProcessQueue q, int* error)
{
    if (q == NULL)
    {
        *error |= NULL_POINTER_ERROR;
        return -1;
    }

    return q->size;
}

/*=================================================================================================
 =  Comment block for function: p_queue_isEmpty()
 =  Programmer names: Evan Phillips, Lucas Cowell, Tony Butterfield
 =  Final test and approval date:
 =  Synopsis:
 =      unsigned short p_queue_isEmpty(ProcessQueue, int*)
 =      Return value ranges: BOOLEAN - true if queue is empty or pointer is null, else false
 =      Parameter value ranges: A pointer to a ProcessQueueStr, pointer to an error flag
 =      Error conditions: returns NULL_POINTER_ERROR if pointer is null.
 =  returns true if there are no processes in the queue.
 =
 ==================================================================================================*/
BOOLEAN p_queue_isEmpty(ProcessQueue q, int* error)
{
    if (q == NULL)
    {
        *error |= NULL_POINTER_ERROR;
        return TRUE;
    }

    if (q->size > 0)
        return FALSE;
    else
        return TRUE;
}
